/*
  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
*/

/* cJSON */
/* JSON parser in C. */

/* disable warnings about old C89 functions in MSVC */
#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
#define _CRT_SECURE_NO_DEPRECATE
#endif

#ifdef __GNUC__
#pragma GCC visibility push(default)
#endif
#if defined(_MSC_VER)
#pragma warning (push)
/* disable warning about single line comments in system headers */
#pragma warning (disable : 4001)
#endif

/* Standard library includes required for cJSON functionality */
/* string.h - Provides string manipulation functions like strlen, strcpy, etc. */
#include <string.h>
/* stdio.h - Provides input/output functions like sprintf, sscanf, etc. */
#include <stdio.h>
/* math.h - Provides mathematical functions like fabs, and constants like NAN */
#include <math.h>
/* stdlib.h - Provides memory allocation functions like malloc, free, etc. */
#include <stdlib.h>
/* limits.h - Provides constants for integer limits like INT_MAX, INT_MIN */
#include <limits.h>
/* ctype.h - Provides character handling functions like tolower, isspace, etc. */
#include <ctype.h>
/* float.h - Provides floating-point constants like DBL_EPSILON */
#include <float.h>

/* Conditional inclusion of locale.h when ENABLE_LOCALES is defined */
/* locale.h - Provides localization functions like localeconv for decimal point handling */
#ifdef ENABLE_LOCALES
#include <locale.h>
#endif

/* Restore previous warning settings for Microsoft Visual C++ */
#if defined(_MSC_VER)
/* Restore the warning settings that were saved with #pragma warning(push) */
#pragma warning (pop)
#endif

/* Restore previous GCC visibility settings */
#ifdef __GNUC__
/* Pop the visibility setting back to what it was before */
#pragma GCC visibility pop
#endif

/* Include the cJSON header file for type definitions and public API declarations */
#include "cJSON.h"

/* Define our own boolean type to ensure consistent behavior across platforms */
/* Undefine true if it's already defined to avoid conflicts */
#ifdef true
#undef true
#endif
/* Define true as 1 cast to cJSON_bool type for consistent boolean representation */
#define true ((cJSON_bool)1)

/* Undefine false if it's already defined to avoid conflicts */
#ifdef false
#undef false
#endif
/* Define false as 0 cast to cJSON_bool type for consistent boolean representation */
#define false ((cJSON_bool)0)

/* Define isnan and isinf for ANSI C compatibility */
/* If isinf is not already defined (e.g., in C99 or above), define our own implementation */
/* This checks if a value is infinite by seeing if (d - d) is NaN but d itself is not NaN */
#ifndef isinf
#define isinf(d) (isnan((d - d)) && !isnan(d))
#endif

/* If isnan is not already defined (e.g., in C99 or above), define our own implementation */
/* A value is NaN if it's not equal to itself */
#ifndef isnan
#define isnan(d) (d != d)
#endif

/* Define NAN (Not A Number) constant if not already defined */
#ifndef NAN
/* On Windows, use sqrt(-1.0) to generate NaN */
#ifdef _WIN32
#define NAN sqrt(-1.0)
#else
/* On other platforms, use 0.0/0.0 to generate NaN */
#define NAN 0.0/0.0
#endif
#endif

/* Define an error structure to track parsing errors */
/* json: pointer to the JSON text where the error occurred */
/* position: offset in bytes from the beginning of json where the error occurred */
typedef struct {
    const unsigned char *json;
    size_t position;
} error;

/* Global error instance initialized to NULL pointer and zero position */
static error global_error = { NULL, 0 };

/* Public API function to get a pointer to the position of the last parsing error */
/* Returns a string pointer pointing to the location in the JSON text where the error occurred */
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
{
    /* Return a pointer to the position in the JSON text where the error occurred */
    /* Cast the result to const char* as the API expects */
    return (const char*) (global_error.json + global_error.position);
}

/* Public API function to safely extract the string value from a cJSON item */
/* Parameter: item - pointer to a cJSON structure that should contain a string */
/* Returns: pointer to the string value if item is a string, NULL otherwise */
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) 
{
    /* Check if the item is actually a string type */
    if (!cJSON_IsString(item)) 
    {
        /* Return NULL if the item is not a string */
        return NULL;
    }

    /* Return the string value stored in the item */
    return item->valuestring;
}

/* Public API function to safely extract the numeric value from a cJSON item */
/* Parameter: item - pointer to a cJSON structure that should contain a number */
/* Returns: the double value if item is a number, NAN otherwise */
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) 
{
    /* Check if the item is actually a number type */
    if (!cJSON_IsNumber(item)) 
    {
        /* Return NaN (Not A Number) if the item is not a number */
        return (double) NAN;
    }

    /* Return the double value stored in the item */
    return item->valuedouble;
}

/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
/* Compile-time check to ensure the cJSON.c and cJSON.h files are from the same version */
/* If major, minor, or patch versions don't match, trigger a compilation error */
#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 15)
    /* Generate a compile-time error if versions don't match */
    #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
#endif

/* Public API function to get the version string of the cJSON library */
/* Returns: a static string containing the version in format "major.minor.patch" */
CJSON_PUBLIC(const char*) cJSON_Version(void)
{
    /* Static buffer to hold the version string (maximum 15 characters including null terminator) */
    static char version[15];
    /* Format the version components into the version string */
    sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);

    /* Return the formatted version string */
    return version;
}

/* Case insensitive string comparison function, doesn't consider two NULL pointers equal though */
/* Parameters: string1 - first string to compare, string2 - second string to compare */
/* Returns: 0 if strings are equal (case insensitive), non-zero difference otherwise, 1 if either is NULL */
static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
{
    /* Check if either string is NULL, return 1 (non-equal) if so */
    if ((string1 == NULL) || (string2 == NULL))
    {
        return 1;
    }

    /* Check if both pointers point to the same memory location, return 0 (equal) if so */
    if (string1 == string2)
    {
        return 0;
    }

    /* Loop while characters match (case insensitive) */
    /* Convert both characters to lowercase before comparing */
    /* Increment both pointers after each comparison */
    for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
    {
        /* If we've reached the end of the string, they're equal */
        if (*string1 == '\0')
        {
            return 0;
        }
    }

    /* Return the ASCII difference between the first mismatched characters (case insensitive) */
    return tolower(*string1) - tolower(*string2);
}

/* Define a structure for internal memory management hooks */
/* This allows customization of memory allocation functions used by cJSON */
/* allocate: function pointer to a malloc-like function that allocates 'size' bytes */
/* deallocate: function pointer to a free-like function that releases memory at 'pointer' */
/* reallocate: function pointer to a realloc-like function that resizes memory at 'pointer' to 'size' bytes */
typedef struct internal_hooks
{
    void *(CJSON_CDECL *allocate)(size_t size);
    void (CJSON_CDECL *deallocate)(void *pointer);
    void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
} internal_hooks;

/* Compiler-specific handling for Microsoft Visual C++ */
#if defined(_MSC_VER)
/* Work around MSVC error C2322: '...' address of dllimport '...' is not static */
/* MSVC requires these wrapper functions to avoid issues with importing DLL functions */

/* Wrapper function for malloc to ensure compatibility with MSVC DLL imports */
static void * CJSON_CDECL internal_malloc(size_t size)
{
    /* Delegate to standard malloc function */
    return malloc(size);
}

/* Wrapper function for free to ensure compatibility with MSVC DLL imports */
static void CJSON_CDECL internal_free(void *pointer)
{
    /* Delegate to standard free function */
    free(pointer);
}

/* Wrapper function for realloc to ensure compatibility with MSVC DLL imports */
static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
{
    /* Delegate to standard realloc function */
    return realloc(pointer, size);
}
#else
/* For non-MSVC compilers, directly map internal functions to standard library functions */
/* Define internal_malloc as a macro that expands to malloc */
#define internal_malloc malloc
/* Define internal_free as a macro that expands to free */
#define internal_free free
/* Define internal_realloc as a macro that expands to realloc */
#define internal_realloc realloc
#endif

/* Macro to calculate strlen of character literals at compile time */
/* This works because sizeof(string_literal) includes the null terminator */
/* sizeof("") is always 1 (just the null terminator) */
/* So sizeof(string_literal) - sizeof("") gives the length without the null terminator */
#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))

/* Global hooks instance initialized with default memory management functions */
/* This provides the default memory allocation, deallocation, and reallocation functions */
static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };

/* Internal function to duplicate a string using the provided memory hooks */
/* Parameters: string - the string to duplicate, hooks - memory management functions to use */
/* Returns: a newly allocated copy of the string, or NULL if allocation fails or string is NULL */
static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
{
    /* Variable to store the length of the string plus null terminator */
    size_t length = 0;
    /* Pointer to the copied string */
    unsigned char *copy = NULL;

    /* Check if the input string is NULL */
    if (string == NULL)
    {
        /* Return NULL if trying to duplicate a NULL string */
        return NULL;
    }

    /* Calculate the length needed (including null terminator) */
    /* strlen gives length without null terminator, so we add sizeof("") which is 1 */
    length = strlen((const char*)string) + sizeof("");
    /* Allocate memory for the copy using the provided allocation hook */
    copy = (unsigned char*)hooks->allocate(length);
    /* Check if memory allocation failed */
    if (copy == NULL)
    {
        /* Return NULL if allocation failed */
        return NULL;
    }
    /* Copy the string content (including null terminator) to the new memory */
    memcpy(copy, string, length);

    /* Return the pointer to the duplicated string */
    return copy;
}

/* Public API function to initialize custom memory management hooks */
/* Parameters: hooks - pointer to cJSON_Hooks structure with custom memory functions */
/* If hooks is NULL, reset to default malloc/free/realloc functions */
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
{
    /* Check if hooks parameter is NULL */
    if (hooks == NULL)
    {
        /* Reset hooks to default standard library functions */
        global_hooks.allocate = malloc;
        global_hooks.deallocate = free;
        global_hooks.reallocate = realloc;
        /* Exit function early */
        return;
    }

    /* Initialize allocate function to default malloc */
    global_hooks.allocate = malloc;
    /* Override with custom malloc function if provided */
    if (hooks->malloc_fn != NULL)
    {
        global_hooks.allocate = hooks->malloc_fn;
    }

    /* Initialize deallocate function to default free */
    global_hooks.deallocate = free;
    /* Override with custom free function if provided */
    if (hooks->free_fn != NULL)
    {
        global_hooks.deallocate = hooks->free_fn;
    }

    /* Use realloc only if both free and malloc are standard library functions */
    /* Set reallocate to NULL initially */
    global_hooks.reallocate = NULL;
    /* Enable realloc only if both allocate and deallocate are standard functions */
    if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
    {
        global_hooks.reallocate = realloc;
    }
}

/* Internal constructor for creating a new cJSON item */
/* Parameters: hooks - memory management functions to use for allocation */
/* Returns: pointer to a newly allocated and zero-initialized cJSON structure, or NULL if allocation fails */
static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
{
    /* Allocate memory for a new cJSON node using the provided allocation hook */
    cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
    /* Check if memory allocation was successful */
    if (node)
    {
        /* Initialize all members of the cJSON structure to zero */
        memset(node, '\0', sizeof(cJSON));
    }

    /* Return the pointer to the new node (NULL if allocation failed) */
    return node;
}

/* Public API function to recursively delete a cJSON structure and all its children */
/* Parameters: item - pointer to the cJSON structure to delete */
/* This function handles all memory deallocation for the cJSON structure and its subtree */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
{
    /* Temporary pointer to store the next sibling before deleting current item */
    cJSON *next = NULL;
    /* Loop through the linked list of cJSON items */
    while (item != NULL)
    {
        /* Store the next sibling before we delete the current item */
        next = item->next;
        /* Recursively delete child items if this item has children and is not a reference */
        if (!(item->type & cJSON_IsReference) && (item->child != NULL))
        {
            cJSON_Delete(item->child);
        }
        /* Deallocate the valuestring if this item has one and is not a reference */
        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
        {
            global_hooks.deallocate(item->valuestring);
        }
        /* Deallocate the string (key name) if this item has one and it's not a constant string */
        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
        {
            global_hooks.deallocate(item->string);
        }
        /* Deallocate the cJSON structure itself */
        global_hooks.deallocate(item);
        /* Move to the next sibling in the linked list */
        item = next;
    }
}

/* Get the decimal point character of the current locale */
/* This is used when parsing and printing floating point numbers */
/* Returns: the decimal point character for the current locale, or '.' if locales are disabled */
static unsigned char get_decimal_point(void)
{
/* Check if locale support is enabled */
#ifdef ENABLE_LOCALES
    /* Get locale-specific formatting information */
    struct lconv *lconv = localeconv();
    /* Return the first character of the locale's decimal point string */
    return (unsigned char) lconv->decimal_point[0];
#else
    /* If locales are disabled, always return the standard decimal point character */
    return '.';
#endif
}

/* Structure to hold state during JSON parsing */
/* content: pointer to the JSON text being parsed */
/* length: total length of the JSON text in bytes */
/* offset: current position in the JSON text */
/* depth: how deeply nested (in arrays/objects) is the input at the current offset */
/* hooks: memory management functions to use during parsing */
typedef struct
{
    const unsigned char *content;
    size_t length;
    size_t offset;
    size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
    internal_hooks hooks;
} parse_buffer;

/* Macro to check if the given size is left to read in a given parse buffer (starting with 1) */
/* Returns true if buffer is valid and there's enough data left to read 'size' bytes */
#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))

/* Macro to check if the buffer can be accessed at the given index (starting with 0) */
/* Returns true if buffer is valid and the index is within bounds */
#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))

/* Macro that negates the result of can_access_at_index */
/* Returns true if buffer is invalid or the index is out of bounds */
#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))

/* Macro to get a pointer to the buffer at the current position */
/* Returns a pointer to the current position in the content */
#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)

/* Parse the input text to generate a number, and populate the result into item. */
/* Parameters: item - cJSON structure to populate with the parsed number */
/*             input_buffer - buffer containing the JSON text to parse */
/* Returns: true if parsing was successful, false otherwise */
static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
{
    /* Variable to store the parsed double value */
    double number = 0;
    /* Pointer to the character after the parsed number */
    unsigned char *after_end = NULL;
    /* Temporary buffer to hold the number as a C string */
    unsigned char number_c_string[64];
    /* Get the decimal point character for the current locale */
    unsigned char decimal_point = get_decimal_point();
    /* Loop counter */
    size_t i = 0;

    /* Validate input parameters */
    if ((input_buffer == NULL) || (input_buffer->content == NULL))
    {
        /* Return false if input parameters are invalid */
        return false;
    }

    /* Copy the number into a temporary buffer and replace '.' with the decimal point
     * of the current locale (for strtod)
     * This also takes care of '\0' not necessarily being available for marking the end of the input */
    /* Loop through characters in the input buffer */
    for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
    {
        /* Process each character based on its type */
        switch (buffer_at_offset(input_buffer)[i])
        {
            /* Handle numeric digits and number-related characters */
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
            case '+':
            case '-':
            case 'e':
            case 'E':
                /* Copy the character directly */
                number_c_string[i] = buffer_at_offset(input_buffer)[i];
                break;

            /* Handle decimal point */
            case '.':
                /* Replace with locale-specific decimal point */
                number_c_string[i] = decimal_point;
                break;

            /* Any other character marks the end of the number */
            default:
                /* Jump to the end of the loop */
                goto loop_end;
        }
    }
/* Label to mark the end of the copying loop */
loop_end:
    /* Null-terminate the C string */
    number_c_string[i] = '\0';

    /* Convert the C string to a double using strtod */
    number = strtod((const char*)number_c_string, (char**)&after_end);
    /* Check if parsing failed (no advancement) */
    if (number_c_string == after_end)
    {
        /* Return false to indicate parse error */
        return false; /* parse_error */
    }

    /* Store the double value in the cJSON item */
    item->valuedouble = number;

    /* Use saturation in case of overflow to fit within int range */
    if (number >= INT_MAX)
    {
        /* Cap at maximum int value */
        item->valueint = INT_MAX;
    }
    else if (number <= (double)INT_MIN)
    {
        /* Cap at minimum int value */
        item->valueint = INT_MIN;
    }
    else
    {
        /* Convert to int normally */
        item->valueint = (int)number;
    }

    /* Set the item type to number */
    item->type = cJSON_Number;

    /* Advance the buffer offset by the number of characters consumed */
    input_buffer->offset += (size_t)(after_end - number_c_string);
    /* Return true to indicate successful parsing */
    return true;
}

/* Helper function to set a number value in a cJSON object */
/* Note: don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
/* Parameters: object - cJSON object to set the number value in */
/*             number - the double value to set */
/* Returns: the double value that was set */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
{
    /* Check for overflow to maximum integer value */
    if (number >= INT_MAX)
    {
        /* Set integer value to maximum representable integer */
        object->valueint = INT_MAX;
    }
    /* Check for underflow to minimum integer value */
    else if (number <= (double)INT_MIN)
    {
        /* Set integer value to minimum representable integer */
        object->valueint = INT_MIN;
    }
    /* Normal case within integer range */
    else
    {
        /* Convert and store the integer value */
        object->valueint = (int)number;
    }

    /* Store and return the double value */
    return object->valuedouble = number;
}

/* Public API function to set the valuestring of a cJSON string object */
/* Parameters: object - cJSON object to set the string value in (must be of type cJSON_String) */
/*             valuestring - the new string value to set */
/* Returns: pointer to the new string value, or NULL if operation failed */
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
{
    /* Pointer to hold a copy of the new string value */
    char *copy = NULL;
    /* If object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
    if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference))
    {
        /* Return NULL if object is not a string or is a reference */
        return NULL;
    }
    /* Check if the new string fits in the existing buffer */
    if (strlen(valuestring) <= strlen(object->valuestring))
    {
        /* Copy the new string into the existing buffer */
        strcpy(object->valuestring, valuestring);
        /* Return pointer to the updated string */
        return object->valuestring;
    }
    /* Create a new copy of the string with proper memory allocation */
    copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
    /* Check if memory allocation failed */
    if (copy == NULL)
    {
        /* Return NULL if allocation failed */
        return NULL;
    }
    /* Free the old string value if it exists */
    if (object->valuestring != NULL)
    {
        cJSON_free(object->valuestring);
    }
    /* Update the object to point to the new string copy */
    object->valuestring = copy;

    /* Return pointer to the new string copy */
    return copy;
}

/* Structure to hold state during JSON printing/generation */
/* buffer: pointer to the output buffer where JSON text is written */
/* length: total allocated length of the buffer in bytes */
/* offset: current position in the buffer where next text will be written */
/* depth: current nesting depth (for formatted printing with indentation) */
/* noalloc: flag indicating if buffer reallocation is forbidden */
/* format: flag indicating if this print should be formatted (with indentation and newlines) */
/* hooks: memory management functions to use during printing */
typedef struct
{
    unsigned char *buffer;
    size_t length;
    size_t offset;
    size_t depth; /* current nesting depth (for formatted printing) */
    cJSON_bool noalloc;
    cJSON_bool format; /* is this print a formatted print */
    internal_hooks hooks;
} printbuffer;

/* Realloc printbuffer if necessary to have at least "needed" bytes more */
/* This function ensures there's enough space in the buffer for additional data */
/* Parameters: p - pointer to the printbuffer structure */
/*             needed - number of additional bytes needed */
/* Returns: pointer to the position in buffer where writing should start, or NULL if failed */
static unsigned char* ensure(printbuffer * const p, size_t needed)
{
    /* Pointer to the new buffer if reallocation is needed */
    unsigned char *newbuffer = NULL;
    /* Variable to store the calculated new buffer size */
    size_t newsize = 0;

    /* Validate input parameters */
    if ((p == NULL) || (p->buffer == NULL))
    {
        /* Return NULL if input parameters are invalid */
        return NULL;
    }

    /* Check if current offset is valid */
    if ((p->length > 0) && (p->offset >= p->length))
    {
        /* Make sure that offset is valid */
        return NULL;
    }

    /* Check if requested size exceeds maximum supported size */
    if (needed > INT_MAX)
    {
        /* Sizes bigger than INT_MAX are currently not supported */
        return NULL;
    }

    /* Calculate total required buffer size */
    needed += p->offset + 1;
    /* Check if current buffer is already large enough */
    if (needed <= p->length)
    {
        /* Return pointer to current position in buffer */
        return p->buffer + p->offset;
    }

    /* Check if reallocation is forbidden */
    if (p->noalloc) {
        /* Return NULL if reallocation is not allowed */
        return NULL;
    }

    /* Calculate new buffer size */
    if (needed > (INT_MAX / 2))
    {
        /* Handle potential overflow of int, use INT_MAX if possible */
        if (needed <= INT_MAX)
        {
            /* Set new size to maximum supported value */
            newsize = INT_MAX;
        }
        else
        {
            /* Return NULL if size exceeds maximum */
            return NULL;
        }
    }
    else
    {
        /* Double the required size for efficiency */
        newsize = needed * 2;
    }

    /* Try to reallocate using the reallocate hook if available */
    if (p->hooks.reallocate != NULL)
    {
        /* Reallocate with realloc if available */
        newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
        /* Check if reallocation failed */
        if (newbuffer == NULL)
        {
            /* Free the old buffer */
            p->hooks.deallocate(p->buffer);
            /* Reset buffer state */
            p->length = 0;
            p->buffer = NULL;

            /* Return NULL to indicate failure */
            return NULL;
        }
    }
    else
    {
        /* Otherwise reallocate manually by allocating new buffer and copying data */
        newbuffer = (unsigned char*)p->hooks.allocate(newsize);
        /* Check if allocation failed */
        if (!newbuffer)
        {
            /* Free the old buffer */
            p->hooks.deallocate(p->buffer);
            /* Reset buffer state */
            p->length = 0;
            p->buffer = NULL;

            /* Return NULL to indicate failure */
            return NULL;
        }
        
        /* Copy existing data to the new buffer */
        memcpy(newbuffer, p->buffer, p->offset + 1);
        /* Free the old buffer */
        p->hooks.deallocate(p->buffer);
    }
    /* Update buffer metadata with new values */
    p->length = newsize;
    p->buffer = newbuffer;

    /* Return pointer to the position where writing should continue */
    return newbuffer + p->offset;
}

/* Calculate the new length of the string in a printbuffer and update the offset */
/* This function updates the buffer's offset to reflect the actual length of the string */
/* Parameters: buffer - pointer to the printbuffer structure to update */
static void update_offset(printbuffer * const buffer)
{
    /* Pointer to the current position in the buffer */
    const unsigned char *buffer_pointer = NULL;
    /* Validate input parameters */
    if ((buffer == NULL) || (buffer->buffer == NULL))
    {
        /* Return early if input parameters are invalid */
        return;
    }
    /* Get pointer to the current position in the buffer */
    buffer_pointer = buffer->buffer + buffer->offset;

    /* Update the offset by adding the length of the string at the current position */
    buffer->offset += strlen((const char*)buffer_pointer);
}

/* securely comparison of floating-point variables */
static cJSON_bool compare_double(double a, double b)
{
    double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
    return (fabs(a - b) <= maxVal * DBL_EPSILON);
}

/* Render the number nicely from the given item into a string. */
/* This function formats a number for JSON output with appropriate precision */
/* Parameters: item - cJSON item containing the number to print */
/*             output_buffer - buffer where the formatted number should be written */
/* Returns: true if successful, false otherwise */
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
{
    /* Pointer to the position in the output buffer where number will be written */
    unsigned char *output_pointer = NULL;
    /* Get the double value from the cJSON item */
    double d = item->valuedouble;
    /* Variable to store the length of the formatted number string */
    int length = 0;
    /* Loop counter */
    size_t i = 0;
    /* Temporary buffer to format the number into a string */
    unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
    /* Get the decimal point character for the current locale */
    unsigned char decimal_point = get_decimal_point();
    /* Variable to test if the formatted number can be parsed back */
    double test = 0.0;

    /* Initialize the number buffer with zeros */
    memset(number_buffer, 0x00, sizeof(number_buffer));

    /* Validate input parameter */
    if (output_buffer == NULL)
    {
        /* Return false if output buffer is invalid */
        return false;
    }

    /* Check for special floating-point values: NaN and Infinity */
    if (isnan(d) || isinf(d))
    {
        /* Format NaN and Infinity as "null" in JSON */
        length = sprintf((char*)number_buffer, "null");
    }
    else
    {
        /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
        length = sprintf((char*)number_buffer, "%1.15g", d);

        /* Check whether the original double can be recovered from the formatted string */
        if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
        {
            /* If not, print with 17 decimal places of precision for better accuracy */
            length = sprintf((char*)number_buffer, "%1.17g", d);
        }
    }

    /* Check if sprintf failed or buffer overrun occurred */
    if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
    {
        /* Return false to indicate failure */
        return false;
    }

    /* Reserve appropriate space in the output buffer */
    output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
    /* Check if buffer allocation failed */
    if (output_pointer == NULL)
    {
        /* Return false to indicate failure */
        return false;
    }

    /* Copy the printed number to the output and replace locale
     * dependent decimal point with '.' */
    for (i = 0; i < ((size_t)length); i++)
    {
        /* Replace locale-specific decimal point with standard JSON decimal point */
        if (number_buffer[i] == decimal_point)
        {
            output_pointer[i] = '.';
            continue;
        }

        /* Copy the character as-is */
        output_pointer[i] = number_buffer[i];
    }
    /* Null-terminate the output string */
    output_pointer[i] = '\0';

    /* Update the buffer offset to reflect the added content */
    output_buffer->offset += (size_t)length;

    /* Return true to indicate success */
    return true;
}

/* Parse a 4-digit hexadecimal number from input */
/* This function is used to decode UTF-16 escape sequences in JSON strings */
/* Parameters: input - pointer to 4 characters representing a hexadecimal number */
/* Returns: the parsed unsigned integer value, or 0 if invalid */
static unsigned parse_hex4(const unsigned char * const input)
{
    /* Variable to accumulate the parsed hexadecimal value */
    unsigned int h = 0;
    /* Loop counter */
    size_t i = 0;

    /* Process each of the 4 hexadecimal digits */
    for (i = 0; i < 4; i++)
    {
        /* Parse each digit based on its character value */
        if ((input[i] >= '0') && (input[i] <= '9'))
        {
            /* Add numeric digit value (0-9) */
            h += (unsigned int) input[i] - '0';
        }
        else if ((input[i] >= 'A') && (input[i] <= 'F'))
        {
            /* Add uppercase hexadecimal digit value (10-15) */
            h += (unsigned int) 10 + input[i] - 'A';
        }
        else if ((input[i] >= 'a') && (input[i] <= 'f'))
        {
            /* Add lowercase hexadecimal digit value (10-15) */
            h += (unsigned int) 10 + input[i] - 'a';
        }
        else /* invalid character */
        {
            /* Return 0 for invalid hexadecimal digit */
            return 0;
        }

        /* Shift left to make place for the next nibble (4 bits) */
        if (i < 3)
        {
            /* Shift left by 4 bits to make room for the next digit */
            h = h << 4;
        }
    }

    /* Return the parsed hexadecimal value */
    return h;
}

/* Converts a UTF-16 literal to UTF-8 */
/* A literal can be one or two sequences of the form \uXXXX */
/* Parameters: input_pointer - pointer to the start of the UTF-16 literal */
/*             input_end - pointer to the end of the input buffer */
/*             output_pointer - pointer to pointer where UTF-8 output should be written */
/* Returns: the length of the processed UTF-16 sequence, or 0 on failure */
static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
{
    /* Unicode codepoint to be encoded */
    long unsigned int codepoint = 0;
    /* First UTF-16 code unit */
    unsigned int first_code = 0;
    /* Pointer to the first UTF-16 sequence */
    const unsigned char *first_sequence = input_pointer;
    /* Length of the UTF-8 encoding needed */
    unsigned char utf8_length = 0;
    /* Position in the UTF-8 encoding */
    unsigned char utf8_position = 0;
    /* Length of the UTF-16 sequence processed */
    unsigned char sequence_length = 0;
    /* First byte marker for multi-byte UTF-8 sequences */
    unsigned char first_byte_mark = 0;

    /* Check if there's enough input for at least one UTF-16 sequence (\uXXXX = 6 characters) */
    if ((input_end - first_sequence) < 6)
    {
        /* Input ends unexpectedly */
        goto fail;
    }

    /* Get the first UTF-16 sequence (skip the \u part) */
    first_code = parse_hex4(first_sequence + 2);

    /* Check that the code is valid (not a low surrogate) */
    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
    {
        /* Low surrogates are not valid as first code unit */
        goto fail;
    }

    /* Check if this is a UTF-16 surrogate pair */
    if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
    {
        /* Point to the second UTF-16 sequence */
        const unsigned char *second_sequence = first_sequence + 6;
        /* Second UTF-16 code unit */
        unsigned int second_code = 0;
        /* Surrogate pairs are 12 characters: \uXXXX\uXXXX */
        sequence_length = 12; /* \uXXXX\uXXXX */

        /* Check if there's enough input for the second sequence */
        if ((input_end - second_sequence) < 6)
        {
            /* Input ends unexpectedly */
            goto fail;
        }

        /* Check if the second sequence starts with \u */
        if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
        {
            /* Missing second half of the surrogate pair */
            goto fail;
        }

        /* Get the second UTF-16 sequence */
        second_code = parse_hex4(second_sequence + 2);
        /* Check that the second code is valid (must be a low surrogate) */
        if ((second_code < 0xDC00) || (second_code > 0xDFFF))
        {
            /* Invalid second half of the surrogate pair */
            goto fail;
        }

        /* Calculate the Unicode codepoint from the surrogate pair */
        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
    }
    else
    {
        /* Single UTF-16 sequence */
        sequence_length = 6; /* \uXXXX */
        codepoint = first_code;
    }

    /* Encode as UTF-8 - takes at maximum 4 bytes to encode:
     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
    if (codepoint < 0x80)
    {
        /* Normal ASCII, encoding 0xxxxxxx */
        utf8_length = 1;
    }
    else if (codepoint < 0x800)
    {
        /* Two bytes, encoding 110xxxxx 10xxxxxx */
        utf8_length = 2;
        first_byte_mark = 0xC0; /* 11000000 */
    }
    else if (codepoint < 0x10000)
    {
        /* Three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
        utf8_length = 3;
        first_byte_mark = 0xE0; /* 11100000 */
    }
    else if (codepoint <= 0x10FFFF)
    {
        /* Four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
        utf8_length = 4;
        first_byte_mark = 0xF0; /* 11110000 */
    }
    else
    {
        /* Invalid Unicode codepoint */
        goto fail;
    }

    /* Encode as UTF-8 */
    for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
    {
        /* Encode continuation bytes with pattern 10xxxxxx */
        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
        /* Shift codepoint right by 6 bits for next byte */
        codepoint >>= 6;
    }
    /* Encode first byte */
    if (utf8_length > 1)
    {
        /* For multi-byte sequences, combine with first byte marker */
        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
    }
    else
    {
        /* For single byte, mask to 7-bit ASCII */
        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
    }

    /* Advance output pointer by the UTF-8 length */
    *output_pointer += utf8_length;

    /* Return the length of the processed UTF-16 sequence */
    return sequence_length;

/* Failure label for error handling */
fail:
    /* Return 0 to indicate failure */
    return 0;
}

/* Parse the input text into an unescaped string, and populate item. */
/* This function handles JSON string parsing including escape sequences and UTF-16 literals */
/* Parameters: item - cJSON item to populate with the parsed string */
/*             input_buffer - buffer containing the JSON text to parse */
/* Returns: true if parsing was successful, false otherwise */
static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
{
    /* Pointer to current position in input buffer (skip opening quote) */
    const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
    /* Pointer to end of string in input buffer */
    const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
    /* Pointer to current position in output buffer */
    unsigned char *output_pointer = NULL;
    /* Pointer to allocated output buffer */
    unsigned char *output = NULL;

    /* Check if this is actually a string (starts with quote) */
    if (buffer_at_offset(input_buffer)[0] != '\"')
    {
        /* Not a string, jump to failure handling */
        goto fail;
    }

    {
        /* Calculate approximate size of the output (overestimate) */
        size_t allocation_length = 0;
        size_t skipped_bytes = 0;
        /* Find the end of the string by scanning for closing quote */
        while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
        {
            /* Check if this is an escape sequence */
            if (input_end[0] == '\\')
            {
                /* Prevent buffer overflow when last input character is a backslash */
                if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
                {
                    /* Prevent buffer overflow when last input character is a backslash */
                    goto fail;
                }
                /* Count escaped characters that won't appear in output */
                skipped_bytes++;
                input_end++;
            }
            input_end++;
        }
        /* Check if string ended unexpectedly (no closing quote) */
        if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
        {
            goto fail; /* string ended unexpectedly */
        }

        /* Calculate maximum needed allocation size (overestimate) */
        allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
        /* Allocate memory for the output string */
        output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
        /* Check if allocation failed */
        if (output == NULL)
        {
            goto fail; /* allocation failure */
        }
    }

    /* Set output pointer to beginning of output buffer */
    output_pointer = output;
    /* Loop through the string literal and process each character */
    while (input_pointer < input_end)
    {
        /* Handle normal characters (not escape sequences) */
        if (*input_pointer != '\\')
        {
            /* Copy character directly to output */
            *output_pointer++ = *input_pointer++;
        }
        /* Handle escape sequences */
        else
        {
            /* Length of the escape sequence (default 2 characters: \ + escaped char) */
            unsigned char sequence_length = 2;
            /* Check if there's enough input for escape sequence */
            if ((input_end - input_pointer) < 1)
            {
                goto fail;
            }

            /* Process different escape sequences */
            switch (input_pointer[1])
            {
                /* Backspace escape */
                case 'b':
                    *output_pointer++ = '\b';
                    break;
                /* Form feed escape */
                case 'f':
                    *output_pointer++ = '\f';
                    break;
                /* Line feed escape */
                case 'n':
                    *output_pointer++ = '\n';
                    break;
                /* Carriage return escape */
                case 'r':
                    *output_pointer++ = '\r';
                    break;
                /* Tab escape */
                case 't':
                    *output_pointer++ = '\t';
                    break;
                /* Literal characters that can be escaped */
                case '\"':
                case '\\':
                case '/':
                    *output_pointer++ = input_pointer[1];
                    break;

                /* UTF-16 literal escape */
                case 'u':
                    /* Convert UTF-16 literal to UTF-8 */
                    sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
                    /* Check if conversion failed */
                    if (sequence_length == 0)
                    {
                        /* Failed to convert UTF16-literal to UTF-8 */
                        goto fail;
                    }
                    break;

                /* Unknown escape sequence */
                default:
                    goto fail;
            }
            input_pointer += sequence_length;
        }
    }

    /* Zero terminate the output string */
    *output_pointer = '\0';

    /* Set item type and value */
    item->type = cJSON_String;
    item->valuestring = (char*)output;

    /* Update input buffer offset to point after the parsed string */
    input_buffer->offset = (size_t) (input_end - input_buffer->content);
    input_buffer->offset++;

    /* Return success */
    return true;

/* Failure handling */
fail:
    /* Deallocate output buffer if it was allocated */
    if (output != NULL)
    {
        input_buffer->hooks.deallocate(output);
    }

    /* Update input buffer offset to point to error position */
    if (input_pointer != NULL)
    {
        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
    }

    /* Return failure */
    return false;
}

/* Render the cstring provided to an escaped version that can be printed. */
/* This function converts a regular C string into a JSON-formatted string with proper escaping */
/* Parameters: input - the input string to be escaped */
/*             output_buffer - the buffer where the escaped string will be written */
/* Returns: true if the operation was successful, false otherwise */
static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
{
    /* Pointer to current position in input string */
    const unsigned char *input_pointer = NULL;
    /* Pointer to output buffer */
    unsigned char *output = NULL;
    /* Pointer to current position in output buffer */
    unsigned char *output_pointer = NULL;
    /* Length of the output string */
    size_t output_length = 0;
    /* Number of additional characters needed for escaping */
    size_t escape_characters = 0;

    /* Validate input parameters */
    if (output_buffer == NULL)
    {
        return false;
    }

    /* Handle empty string case */
    if (input == NULL)
    {
        /* Allocate space for empty JSON string "" */
        output = ensure(output_buffer, sizeof("\"\""));
        if (output == NULL)
        {
            return false;
        }
        /* Copy empty string literal */
        strcpy((char*)output, "\"\"");

        return true;
    }

    /* Count characters that need to be escaped */
    for (input_pointer = input; *input_pointer; input_pointer++)
    {
        /* Check for characters that require escaping */
        switch (*input_pointer)
        {
            case '\"':
            case '\\':
            case '\b':
            case '\f':
            case '\n':
            case '\r':
            case '\t':
                /* Each of these requires one additional escape character */
                escape_characters++;
                break;
            default:
                /* Check for control characters (ASCII < 32) */
                if (*input_pointer < 32)
                {
                    /* UTF-16 escape sequence uXXXX requires 5 additional characters */
                    escape_characters += 5;
                }
                break;
        }
    }
    /* Calculate total output length: original length + escape characters */
    output_length = (size_t)(input_pointer - input) + escape_characters;

    /* Ensure output buffer has enough space (including quotes and null terminator) */
    output = ensure(output_buffer, output_length + sizeof("\"\""));
    if (output == NULL)
    {
        return false;
    }

    /* Optimize for strings that don't need escaping */
    if (escape_characters == 0)
    {
        /* Add opening quote */
        output[0] = '\"';
        /* Copy the entire string */
        memcpy(output + 1, input, output_length);
        /* Add closing quote and null terminator */
        output[output_length + 1] = '\"';
        output[output_length + 2] = '\0';

        return true;
    }

    /* Handle strings that need escaping */
    /* Add opening quote */
    output[0] = '\"';
    /* Set output pointer to position after opening quote */
    output_pointer = output + 1;
    /* Process each character in the input string */
    for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
    {
        /* Check if character can be copied directly */
        if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
        {
            /* Normal character, copy directly */
            *output_pointer = *input_pointer;
        }
        else
        {
            /* Character needs to be escaped */
            /* Add escape character */
            *output_pointer++ = '\\';
            /* Handle different escape cases */
            switch (*input_pointer)
            {
                case '\\':
                    *output_pointer = '\\';
                    break;
                case '\"':
                    *output_pointer = '\"';
                    break;
                case '\b':
                    *output_pointer = 'b';
                    break;
                case '\f':
                    *output_pointer = 'f';
                    break;
                case '\n':
                    *output_pointer = 'n';
                    break;
                case '\r':
                    *output_pointer = 'r';
                    break;
                case '\t':
                    *output_pointer = 't';
                    break;
                default:
                    /* Escape and print as unicode codepoint */
                    sprintf((char*)output_pointer, "u%04x", *input_pointer);
                    /* Advance output pointer by 4 characters (uXXXX) */
                    output_pointer += 4;
                    break;
            }
        }
    }
    /* Add closing quote and null terminator */
    output[output_length + 1] = '\"';
    output[output_length + 2] = '\0';

    /* Return success */
    return true;
}

/* Invoke print_string_ptr (which is useful) on an item. */
/* This function is a wrapper that prints a cJSON string item by calling print_string_ptr */
/* Parameters: item - the cJSON string item to print */
/*             p - the print buffer to write to */
/* Returns: true if the operation was successful, false otherwise */
static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
{
    /* Delegate to print_string_ptr with the item's valuestring */
    return print_string_ptr((unsigned char*)item->valuestring, p);
}

/* Predeclare these prototypes. */
static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);

/* Utility to jump whitespace and cr/lf */
/* This function skips whitespace characters (space, tab, newline, carriage return) in the parse buffer */
/* Parameters: buffer - the parse buffer to process */
/* Returns: pointer to the buffer if successful, NULL if buffer is invalid */
static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
{
    /* Validate input buffer */
    if ((buffer == NULL) || (buffer->content == NULL))
    {
        return NULL;
    }

    /* Check if we can access the first character */
    if (cannot_access_at_index(buffer, 0))
    {
        return buffer;
    }

    /* Skip whitespace characters (ASCII values <= 32 include space, tab, newline, carriage return, etc.) */
    while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
    {
       buffer->offset++;
    }

    /* Prevent buffer overflow by checking if we've gone past the end */
    if (buffer->offset == buffer->length)
    {
        buffer->offset--;
    }

    /* Return the updated buffer */
    return buffer;
}

/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
/* This function skips the UTF-8 Byte Order Mark (BOM) if present at the beginning of the buffer */
/* The UTF-8 BOM is a sequence of three bytes: 0xEF, 0xBB, 0xBF */
/* Parameters: buffer - the parse buffer to process */
/* Returns: pointer to the buffer if successful, NULL if buffer is invalid or not at beginning */
static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
{
    /* Validate input buffer and ensure we're at the beginning of the buffer */
    if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
    {
        return NULL;
    }

    /* Check if we have at least 4 bytes available and if the first 3 bytes match the UTF-8 BOM */
    if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
    {
        /* Skip the 3-byte BOM sequence */
        buffer->offset += 3;
    }

    /* Return the updated buffer */
    return buffer;
}

/* Parse a JSON string with options */
/* This function parses a JSON string and allows specifying whether the string must be null-terminated */
/* Parameters: value - the JSON string to parse */
/*             return_parse_end - if not NULL, will be set to point to the end of the parsed JSON */
/*             require_null_terminated - if true, the JSON string must be null-terminated */
/* Returns: a pointer to the parsed cJSON structure, or NULL if parsing failed */
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
{
    /* Length of the input buffer */
    size_t buffer_length;

    /* Check for null input */
    if (NULL == value)
    {
        return NULL;
    }

    /* Calculate buffer length including null terminator */
    buffer_length = strlen(value) + sizeof("");

    /* Delegate to cJSON_ParseWithLengthOpts with calculated length */
    return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
}

/* Parse an object - create a new root, and populate. */
/* This function parses a JSON string with a specified length and options */
/* Parameters: value - the JSON string to parse */
/*             buffer_length - the length of the JSON string */
/*             return_parse_end - if not NULL, will be set to point to the end of the parsed JSON */
/*             require_null_terminated - if true, the JSON string must be null-terminated */
/* Returns: a pointer to the parsed cJSON structure, or NULL if parsing failed */
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)
{
    /* Parse buffer structure to hold parsing state */
    parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
    /* Root cJSON item to be returned */
    cJSON *item = NULL;

    /* Reset error position for new parsing attempt */
    global_error.json = NULL;
    global_error.position = 0;

    /* Validate input parameters */
    if (value == NULL || 0 == buffer_length)
    {
        goto fail;
    }

    /* Initialize the parse buffer */
    buffer.content = (const unsigned char*)value;
    buffer.length = buffer_length; 
    buffer.offset = 0;
    buffer.hooks = global_hooks;

    /* Create a new cJSON item for the root */
    item = cJSON_New_Item(&global_hooks);
    if (item == NULL) /* memory allocation failed */
    {
        goto fail;
    }

    /* Parse the JSON value, skipping UTF-8 BOM and whitespace */
    if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
    {
        /* Parse failure */
        goto fail;
    }

    /* If we require null-terminated JSON without appended garbage, skip whitespace and check for null terminator */
    if (require_null_terminated)
    {
        /* Skip any trailing whitespace */
        buffer_skip_whitespace(&buffer);
        /* Check if we're at the end of the buffer or if the next character is not a null terminator */
        if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
        {
            goto fail;
        }
    }
    
    /* If return_parse_end is provided, set it to point to the end of the parsed JSON */
    if (return_parse_end)
    {
        *return_parse_end = (const char*)buffer_at_offset(&buffer);
    }

    /* Return the parsed cJSON item */
    return item;

/* Error handling */
fail:
    /* Clean up the cJSON item if it was created */
    if (item != NULL)
    {
        cJSON_Delete(item);
    }

    /* Set error information if value is not NULL */
    if (value != NULL)
    {
        /* Local error structure to hold error information */
        error local_error;
        local_error.json = (const unsigned char*)value;
        local_error.position = 0;

        /* Determine the error position */
        if (buffer.offset < buffer.length)
        {
            local_error.position = buffer.offset;
        }
        else if (buffer.length > 0)
        {
            local_error.position = buffer.length - 1;
        }

        /* Set return_parse_end to point to the error position if provided */
        if (return_parse_end != NULL)
        {
            *return_parse_end = (const char*)local_error.json + local_error.position;
        }

        /* Update global error information */
        global_error = local_error;
    }

    /* Return NULL to indicate parsing failure */
    return NULL;
}

/* Default options for cJSON_Parse */
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
{
    return cJSON_ParseWithOpts(value, 0, 0);
}

CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length)
{
    return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
}

#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))

/* Render a cJSON item/entity/structure to text. */
/* This function converts a cJSON structure into a JSON string representation */
/* Parameters: item - the cJSON item to convert to a JSON string */
/*             format - whether to format the output with indentation and newlines */
/*             hooks - memory management hooks to use */
/* Returns: a pointer to a newly allocated string containing the JSON representation, */
/*          or NULL if the conversion failed. The caller is responsible for freeing the memory. */
static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
{
    /* Default buffer size for initial allocation */
    static const size_t default_buffer_size = 256;
    /* Print buffer structure to hold the output */
    printbuffer buffer[1];
    /* Pointer to the final printed string */
    unsigned char *printed = NULL;

    /* Initialize the buffer structure */
    memset(buffer, 0, sizeof(buffer));

    /* Create initial buffer */
    buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
    buffer->length = default_buffer_size;
    buffer->format = format;
    buffer->hooks = *hooks;
    /* Check if buffer allocation failed */
    if (buffer->buffer == NULL)
    {
        goto fail;
    }

    /* Print the cJSON value to the buffer */
    if (!print_value(item, buffer))
    {
        goto fail;
    }

    /* Update the buffer offset to reflect the actual content length */
    update_offset(buffer);


    /* Check if reallocate function is available for optimization */
    if (hooks->reallocate != NULL)
    {
        /* Try to reallocate the buffer to the exact size needed */
        printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
        if (printed == NULL) {
            goto fail;
        }
        /* Set buffer->buffer to NULL to prevent double-free in cleanup */
        buffer->buffer = NULL;
    }
    else /* Otherwise copy the JSON over to a new buffer of the exact size */
    {
        /* Allocate a new buffer of the exact size needed */
        printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
        if (printed == NULL)
        {
            goto fail;
        }
        /* Copy the content to the new buffer */
        memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
        printed[buffer->offset] = '\0'; /* Null-terminate the string */

        /* Free the original buffer */
        hooks->deallocate(buffer->buffer);
    }

    /* Return the printed string */
    return printed;

/* Error handling path */
fail:
    /* Clean up the buffer if it was allocated */
    if (buffer->buffer != NULL)
    {
        hooks->deallocate(buffer->buffer);
    }

    /* Clean up the printed string if it was allocated */
    if (printed != NULL)
    {
        hooks->deallocate(printed);
    }

    /* Return NULL to indicate failure */
    return NULL;
}

/* Render a cJSON item/entity/structure to text. */
/* This function converts a cJSON structure into a formatted JSON string */
/* Parameters: item - the cJSON item to convert to a JSON string */
/* Returns: a pointer to a newly allocated string containing the JSON representation, */
/*          or NULL if the conversion failed. The caller is responsible for freeing the memory. */
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
{
    /* Call the internal print function with formatting enabled */
    return (char*)print(item, true, &global_hooks);
}

CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
{
    return (char*)print(item, false, &global_hooks);
}

CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
{
    printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };

    if (prebuffer < 0)
    {
        return NULL;
    }

    p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
    if (!p.buffer)
    {
        return NULL;
    }

    p.length = (size_t)prebuffer;
    p.offset = 0;
    p.noalloc = false;
    p.format = fmt;
    p.hooks = global_hooks;

    if (!print_value(item, &p))
    {
        global_hooks.deallocate(p.buffer);
        return NULL;
    }

    return (char*)p.buffer;
}

CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
{
    printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };

    if ((length < 0) || (buffer == NULL))
    {
        return false;
    }

    p.buffer = (unsigned char*)buffer;
    p.length = (size_t)length;
    p.offset = 0;
    p.noalloc = true;
    p.format = format;
    p.hooks = global_hooks;

    return print_value(item, &p);
}

/* Parser core - when encountering text, process appropriately. */
/* This function is the core parser that determines the type of JSON value and parses it accordingly */
/* Parameters: item - the cJSON structure to populate with parsed data */
/*             input_buffer - the buffer containing the JSON text to parse */
/* Returns: true if parsing was successful, false otherwise */
static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
{
    /* Validate input parameters */
    if ((input_buffer == NULL) || (input_buffer->content == NULL))
    {
        return false; /* no input */
    }

    /* Parse the different types of values based on the first character */
    /* Check for null value */
    if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
    {
        item->type = cJSON_NULL;
        input_buffer->offset += 4;
        return true;
    }
    /* Check for false value */
    if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
    {
        item->type = cJSON_False;
        input_buffer->offset += 5;
        return true;
    }
    /* Check for true value */
    if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
    {
        item->type = cJSON_True;
        item->valueint = 1;
        input_buffer->offset += 4;
        return true;
    }
    /* Check for string value (starts with quotation mark) */
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
    {
        return parse_string(item, input_buffer);
    }
    /* Check for number value (starts with minus sign or digit) */
    if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
    {
        return parse_number(item, input_buffer);
    }
    /* Check for array (starts with opening bracket) */
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
    {
        return parse_array(item, input_buffer);
    }
    /* Check for object (starts with opening brace) */
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
    {
        return parse_object(item, input_buffer);
    }

    /* If none of the above, it's an invalid value */
    return false;
}

/* Render a value to text. */
static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
{
    unsigned char *output = NULL;

    if ((item == NULL) || (output_buffer == NULL))
    {
        return false;
    }

    switch ((item->type) & 0xFF)
    {
        case cJSON_NULL:
            output = ensure(output_buffer, 5);
            if (output == NULL)
            {
                return false;
            }
            strcpy((char*)output, "null");
            return true;

        case cJSON_False:
            output = ensure(output_buffer, 6);
            if (output == NULL)
            {
                return false;
            }
            strcpy((char*)output, "false");
            return true;

        case cJSON_True:
            output = ensure(output_buffer, 5);
            if (output == NULL)
            {
                return false;
            }
            strcpy((char*)output, "true");
            return true;

        case cJSON_Number:
            return print_number(item, output_buffer);

        case cJSON_Raw:
        {
            size_t raw_length = 0;
            if (item->valuestring == NULL)
            {
                return false;
            }

            raw_length = strlen(item->valuestring) + sizeof("");
            output = ensure(output_buffer, raw_length);
            if (output == NULL)
            {
                return false;
            }
            memcpy(output, item->valuestring, raw_length);
            return true;
        }

        case cJSON_String:
            return print_string(item, output_buffer);

        case cJSON_Array:
            return print_array(item, output_buffer);

        case cJSON_Object:
            return print_object(item, output_buffer);

        default:
            return false;
    }
}

/* Build an array from input text. */
/* This function parses a JSON array from the input buffer and populates the cJSON item */
/* Parameters: item - the cJSON structure to populate with the parsed array */
/*             input_buffer - the buffer containing the JSON array text to parse */
/* Returns: true if parsing was successful, false otherwise */
static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
{
    /* Head of the linked list of array elements */
    cJSON *head = NULL; 
    /* Current item in the linked list */
    cJSON *current_item = NULL;

    /* Check for nesting limit to prevent stack overflow */
    if (input_buffer->depth >= CJSON_NESTING_LIMIT)
    {
        return false; /* too deeply nested */
    }
    /* Increase nesting depth */
    input_buffer->depth++;

    /* Verify the buffer starts with an opening bracket */
    if (buffer_at_offset(input_buffer)[0] != '[')
    {
        /* not an array */
        goto fail;
    }

    /* Move past the opening bracket */
    input_buffer->offset++;
    /* Skip any whitespace after the opening bracket */
    buffer_skip_whitespace(input_buffer);
    /* Check for empty array (closing bracket immediately after opening) */
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
    {
        /* empty array */
        goto success;
    }

    /* Check if we've reached the end of the buffer unexpectedly */
    if (cannot_access_at_index(input_buffer, 0))
    {
        input_buffer->offset--;
        goto fail;
    }

    /* Step back to character in front of the first element */
    input_buffer->offset--;
    /* Loop through the comma separated array elements */
    do
    {
        /* Allocate next item for the array */
        cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
        if (new_item == NULL)
        {
            goto fail; /* allocation failure */
        }

        /* Attach next item to the linked list */
        if (head == NULL)
        {
            /* Start the linked list with the first item */
            current_item = head = new_item;
        }
        else
        {
            /* Add to the end of the list and advance */
            current_item->next = new_item;
            new_item->prev = current_item;
            current_item = new_item;
        }

        /* Parse the next value in the array */
        input_buffer->offset++;
        buffer_skip_whitespace(input_buffer);
        if (!parse_value(current_item, input_buffer))
        {
            goto fail; /* failed to parse value */
        }
        buffer_skip_whitespace(input_buffer);
    }
    /* Continue as long as there's a comma (more elements to parse) */
    while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));

    /* Verify we have a closing bracket at the end of the array */
    if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
    {
        goto fail; /* expected end of array */
    }

/* Success path - finalize the array */
success:
    /* Decrease nesting depth */
    input_buffer->depth--;

    /* Set up circular linked list for the array elements */
    if (head != NULL) {
        head->prev = current_item;
    }

    /* Set the item type and child pointer */
    item->type = cJSON_Array;
    item->child = head;

    /* Move past the closing bracket */
    input_buffer->offset++;

    return true;

/* Error handling path - clean up allocated memory */
fail:
    /* Clean up any allocated array elements */
    if (head != NULL)
    {
        cJSON_Delete(head);
    }

    return false;
}

/* Render an array to text */
static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
{
    unsigned char *output_pointer = NULL;
    size_t length = 0;
    cJSON *current_element = item->child;

    if (output_buffer == NULL)
    {
        return false;
    }

    /* Compose the output array. */
    /* opening square bracket */
    output_pointer = ensure(output_buffer, 1);
    if (output_pointer == NULL)
    {
        return false;
    }

    *output_pointer = '[';
    output_buffer->offset++;
    output_buffer->depth++;

    while (current_element != NULL)
    {
        if (!print_value(current_element, output_buffer))
        {
            return false;
        }
        update_offset(output_buffer);
        if (current_element->next)
        {
            length = (size_t) (output_buffer->format ? 2 : 1);
            output_pointer = ensure(output_buffer, length + 1);
            if (output_pointer == NULL)
            {
                return false;
            }
            *output_pointer++ = ',';
            if(output_buffer->format)
            {
                *output_pointer++ = ' ';
            }
            *output_pointer = '\0';
            output_buffer->offset += length;
        }
        current_element = current_element->next;
    }

    output_pointer = ensure(output_buffer, 2);
    if (output_pointer == NULL)
    {
        return false;
    }
    *output_pointer++ = ']';
    *output_pointer = '\0';
    output_buffer->depth--;

    return true;
}

/* Build an object from the text. */
/* This function parses a JSON object from the input buffer and populates the cJSON item */
/* Parameters: item - the cJSON structure to populate with the parsed object */
/*             input_buffer - the buffer containing the JSON object text to parse */
/* Returns: true if parsing was successful, false otherwise */
static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
{
    /* Head of the linked list of object members */
    cJSON *head = NULL; 
    /* Current item in the linked list */
    cJSON *current_item = NULL;

    /* Check for nesting limit to prevent stack overflow */
    if (input_buffer->depth >= CJSON_NESTING_LIMIT)
    {
        return false; /* too deeply nested */
    }
    /* Increase nesting depth */
    input_buffer->depth++;

    /* Verify the buffer starts with an opening brace */
    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
    {
        goto fail; /* not an object */
    }

    /* Move past the opening brace */
    input_buffer->offset++;
    /* Skip any whitespace after the opening brace */
    buffer_skip_whitespace(input_buffer);
    /* Check for empty object (closing brace immediately after opening) */
    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
    {
        goto success; /* empty object */
    }

    /* Check if we've reached the end of the buffer unexpectedly */
    if (cannot_access_at_index(input_buffer, 0))
    {
        input_buffer->offset--;
        goto fail;
    }

    /* Step back to character in front of the first element */
    input_buffer->offset--;
    /* Loop through the comma separated object members */
    do
    {
        /* Allocate next item for the object */
        cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
        if (new_item == NULL)
        {
            goto fail; /* allocation failure */
        }

        /* Attach next item to the linked list */
        if (head == NULL)
        {
            /* Start the linked list with the first item */
            current_item = head = new_item;
        }
        else
        {
            /* Add to the end of the list and advance */
            current_item->next = new_item;
            new_item->prev = current_item;
            current_item = new_item;
        }

        /* Parse the name of the child (object key) */
        input_buffer->offset++;
        buffer_skip_whitespace(input_buffer);
        if (!parse_string(current_item, input_buffer))
        {
            goto fail; /* failed to parse name */
        }
        buffer_skip_whitespace(input_buffer);

        /* Swap valuestring and string, because we parsed the name */
        current_item->string = current_item->valuestring;
        current_item->valuestring = NULL;

        /* Verify we have a colon separator between key and value */
        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
        {
            goto fail; /* invalid object */
        }

        /* Parse the value associated with the key */
        input_buffer->offset++;
        buffer_skip_whitespace(input_buffer);
        if (!parse_value(current_item, input_buffer))
        {
            goto fail; /* failed to parse value */
        }
        buffer_skip_whitespace(input_buffer);
    }
    /* Continue as long as there's a comma (more members to parse) */
    while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));

    /* Verify we have a closing brace at the end of the object */
    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
    {
        goto fail; /* expected end of object */
    }

/* Success path - finalize the object */
success:
    /* Decrease nesting depth */
    input_buffer->depth--;

    /* Set up circular linked list for the object members */
    if (head != NULL) {
        head->prev = current_item;
    }

    /* Set the item type and child pointer */
    item->type = cJSON_Object;
    item->child = head;

    /* Move past the closing brace */
    input_buffer->offset++;
    return true;

/* Error handling path - clean up allocated memory */
fail:
    /* Clean up any allocated object members */
    if (head != NULL)
    {
        cJSON_Delete(head);
    }

    return false;
}

/* Render an object to text. */
static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
{
    unsigned char *output_pointer = NULL;
    size_t length = 0;
    cJSON *current_item = item->child;

    if (output_buffer == NULL)
    {
        return false;
    }

    /* Compose the output: */
    length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
    output_pointer = ensure(output_buffer, length + 1);
    if (output_pointer == NULL)
    {
        return false;
    }

    *output_pointer++ = '{';
    output_buffer->depth++;
    if (output_buffer->format)
    {
        *output_pointer++ = '\n';
    }
    output_buffer->offset += length;

    while (current_item)
    {
        if (output_buffer->format)
        {
            size_t i;
            output_pointer = ensure(output_buffer, output_buffer->depth);
            if (output_pointer == NULL)
            {
                return false;
            }
            for (i = 0; i < output_buffer->depth; i++)
            {
                *output_pointer++ = '\t';
            }
            output_buffer->offset += output_buffer->depth;
        }

        /* print key */
        if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
        {
            return false;
        }
        update_offset(output_buffer);

        length = (size_t) (output_buffer->format ? 2 : 1);
        output_pointer = ensure(output_buffer, length);
        if (output_pointer == NULL)
        {
            return false;
        }
        *output_pointer++ = ':';
        if (output_buffer->format)
        {
            *output_pointer++ = '\t';
        }
        output_buffer->offset += length;

        /* print value */
        if (!print_value(current_item, output_buffer))
        {
            return false;
        }
        update_offset(output_buffer);

        /* print comma if not last */
        length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
        output_pointer = ensure(output_buffer, length + 1);
        if (output_pointer == NULL)
        {
            return false;
        }
        if (current_item->next)
        {
            *output_pointer++ = ',';
        }

        if (output_buffer->format)
        {
            *output_pointer++ = '\n';
        }
        *output_pointer = '\0';
        output_buffer->offset += length;

        current_item = current_item->next;
    }

    output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
    if (output_pointer == NULL)
    {
        return false;
    }
    if (output_buffer->format)
    {
        size_t i;
        for (i = 0; i < (output_buffer->depth - 1); i++)
        {
            *output_pointer++ = '\t';
        }
    }
    *output_pointer++ = '}';
    *output_pointer = '\0';
    output_buffer->depth--;

    return true;
}

/* Get Array size/item / object item. */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
{
    cJSON *child = NULL;
    size_t size = 0;

    if (array == NULL)
    {
        return 0;
    }

    child = array->child;

    while(child != NULL)
    {
        size++;
        child = child->next;
    }

    /* FIXME: Can overflow here. Cannot be fixed without breaking the API */

    return (int)size;
}

static cJSON* get_array_item(const cJSON *array, size_t index)
{
    cJSON *current_child = NULL;

    if (array == NULL)
    {
        return NULL;
    }

    current_child = array->child;
    while ((current_child != NULL) && (index > 0))
    {
        index--;
        current_child = current_child->next;
    }

    return current_child;
}

CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
{
    if (index < 0)
    {
        return NULL;
    }

    return get_array_item(array, (size_t)index);
}

static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
{
    cJSON *current_element = NULL;

    if ((object == NULL) || (name == NULL))
    {
        return NULL;
    }

    current_element = object->child;
    if (case_sensitive)
    {
        while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
        {
            current_element = current_element->next;
        }
    }
    else
    {
        while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
        {
            current_element = current_element->next;
        }
    }

    if ((current_element == NULL) || (current_element->string == NULL)) {
        return NULL;
    }

    return current_element;
}

CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
{
    return get_object_item(object, string, false);
}

CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
{
    return get_object_item(object, string, true);
}

CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
{
    return cJSON_GetObjectItem(object, string) ? 1 : 0;
}

/* Utility for array list handling. */
static void suffix_object(cJSON *prev, cJSON *item)
{
    prev->next = item;
    item->prev = prev;
}

/* Utility for handling references. */
static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
{
    cJSON *reference = NULL;
    if (item == NULL)
    {
        return NULL;
    }

    reference = cJSON_New_Item(hooks);
    if (reference == NULL)
    {
        return NULL;
    }

    memcpy(reference, item, sizeof(cJSON));
    reference->string = NULL;
    reference->type |= cJSON_IsReference;
    reference->next = reference->prev = NULL;
    return reference;
}

static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
{
    cJSON *child = NULL;

    if ((item == NULL) || (array == NULL) || (array == item))
    {
        return false;
    }

    child = array->child;
    /*
     * To find the last item in array quickly, we use prev in array
     */
    if (child == NULL)
    {
        /* list is empty, start new one */
        array->child = item;
        item->prev = item;
        item->next = NULL;
    }
    else
    {
        /* append to the end */
        if (child->prev)
        {
            suffix_object(child->prev, item);
            array->child->prev = item;
        }
    }

    return true;
}

/* Add item to array/object. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item)
{
    return add_item_to_array(array, item);
}

#if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
    #pragma GCC diagnostic push
#endif
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
/* helper function to cast away const */
static void* cast_away_const(const void* string)
{
    return (void*)string;
}
#if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
    #pragma GCC diagnostic pop
#endif


/* Add an item to an object with the given string as the key */
/* This function adds an item to an object, setting the item's string field to the provided string */
/* Parameters: object - the cJSON object to add the item to */
/*             string - the key/name for the item */
/*             item - the cJSON item to add to the object */
/*             hooks - memory management hooks to use */
/*             constant_key - whether the key string is constant (not to be copied) */
/* Returns: true if the item was successfully added, false otherwise */
static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
{
    /* New key string for the item */
    char *new_key = NULL;
    /* New type for the item */
    int new_type = cJSON_Invalid;

    /* Validate input parameters */
    if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item))
    {
        return false;
    }

    /* Handle constant vs. copied keys */
    if (constant_key)
    {
        /* Use the string directly without copying (constant key) */
        new_key = (char*)cast_away_const(string);
        new_type = item->type | cJSON_StringIsConst;
    }
    else
    {
        /* Duplicate the string (non-constant key) */
        new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
        if (new_key == NULL)
        {
            return false;
        }

        new_type = item->type & ~cJSON_StringIsConst;
    }

    /* Free the old string if it exists and is not constant */
    if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
    {
        hooks->deallocate(item->string);
    }

    /* Set the item's key and type */
    item->string = new_key;
    item->type = new_type;

    /* Add the item to the object (as an array internally) */
    return add_item_to_array(object, item);
}

/* Add an item to an object with the given string as the key */
/* This is a public API function that adds an item to an object, copying the key string */
/* Parameters: object - the cJSON object to add the item to */
/*             string - the key/name for the item (will be copied) */
/*             item - the cJSON item to add to the object */
/* Returns: true if the item was successfully added, false otherwise */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
{
    /* Delegate to the internal function with global hooks and non-constant key */
    return add_item_to_object(object, string, item, &global_hooks, false);
}

/* Add an item to an object with constant string as key */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
{
    return add_item_to_object(object, string, item, &global_hooks, true);
}

CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
{
    if (array == NULL)
    {
        return false;
    }

    return add_item_to_array(array, create_reference(item, &global_hooks));
}

CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
{
    if ((object == NULL) || (string == NULL))
    {
        return false;
    }

    return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
}

CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
{
    cJSON *null = cJSON_CreateNull();
    if (add_item_to_object(object, name, null, &global_hooks, false))
    {
        return null;
    }

    cJSON_Delete(null);
    return NULL;
}

CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
{
    cJSON *true_item = cJSON_CreateTrue();
    if (add_item_to_object(object, name, true_item, &global_hooks, false))
    {
        return true_item;
    }

    cJSON_Delete(true_item);
    return NULL;
}

CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
{
    cJSON *false_item = cJSON_CreateFalse();
    if (add_item_to_object(object, name, false_item, &global_hooks, false))
    {
        return false_item;
    }

    cJSON_Delete(false_item);
    return NULL;
}

CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
{
    cJSON *bool_item = cJSON_CreateBool(boolean);
    if (add_item_to_object(object, name, bool_item, &global_hooks, false))
    {
        return bool_item;
    }

    cJSON_Delete(bool_item);
    return NULL;
}

CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
{
    cJSON *number_item = cJSON_CreateNumber(number);
    if (add_item_to_object(object, name, number_item, &global_hooks, false))
    {
        return number_item;
    }

    cJSON_Delete(number_item);
    return NULL;
}

CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
{
    cJSON *string_item = cJSON_CreateString(string);
    if (add_item_to_object(object, name, string_item, &global_hooks, false))
    {
        return string_item;
    }

    cJSON_Delete(string_item);
    return NULL;
}

CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
{
    cJSON *raw_item = cJSON_CreateRaw(raw);
    if (add_item_to_object(object, name, raw_item, &global_hooks, false))
    {
        return raw_item;
    }

    cJSON_Delete(raw_item);
    return NULL;
}

CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
{
    cJSON *object_item = cJSON_CreateObject();
    if (add_item_to_object(object, name, object_item, &global_hooks, false))
    {
        return object_item;
    }

    cJSON_Delete(object_item);
    return NULL;
}

CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
{
    cJSON *array = cJSON_CreateArray();
    if (add_item_to_object(object, name, array, &global_hooks, false))
    {
        return array;
    }

    cJSON_Delete(array);
    return NULL;
}

CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
{
    if ((parent == NULL) || (item == NULL))
    {
        return NULL;
    }

    if (item != parent->child)
    {
        /* not the first element */
        item->prev->next = item->next;
    }
    if (item->next != NULL)
    {
        /* not the last element */
        item->next->prev = item->prev;
    }

    if (item == parent->child)
    {
        /* first element */
        parent->child = item->next;
    }
    else if (item->next == NULL)
    {
        /* last element */
        parent->child->prev = item->prev;
    }

    /* make sure the detached item doesn't point anywhere anymore */
    item->prev = NULL;
    item->next = NULL;

    return item;
}

CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
{
    if (which < 0)
    {
        return NULL;
    }

    return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
}

CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
{
    cJSON_Delete(cJSON_DetachItemFromArray(array, which));
}

CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
{
    cJSON *to_detach = cJSON_GetObjectItem(object, string);

    return cJSON_DetachItemViaPointer(object, to_detach);
}

CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
{
    cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);

    return cJSON_DetachItemViaPointer(object, to_detach);
}

CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
{
    cJSON_Delete(cJSON_DetachItemFromObject(object, string));
}

CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
{
    cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
}

/* Replace array/object items with new ones. */
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
{
    cJSON *after_inserted = NULL;

    if (which < 0)
    {
        return false;
    }

    after_inserted = get_array_item(array, (size_t)which);
    if (after_inserted == NULL)
    {
        return add_item_to_array(array, newitem);
    }

    newitem->next = after_inserted;
    newitem->prev = after_inserted->prev;
    after_inserted->prev = newitem;
    if (after_inserted == array->child)
    {
        array->child = newitem;
    }
    else
    {
        newitem->prev->next = newitem;
    }
    return true;
}

CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
{
    if ((parent == NULL) || (replacement == NULL) || (item == NULL))
    {
        return false;
    }

    if (replacement == item)
    {
        return true;
    }

    replacement->next = item->next;
    replacement->prev = item->prev;

    if (replacement->next != NULL)
    {
        replacement->next->prev = replacement;
    }
    if (parent->child == item)
    {
        if (parent->child->prev == parent->child)
        {
            replacement->prev = replacement;
        }
        parent->child = replacement;
    }
    else
    {   /*
         * To find the last item in array quickly, we use prev in array.
         * We can't modify the last item's next pointer where this item was the parent's child
         */
        if (replacement->prev != NULL)
        {
            replacement->prev->next = replacement;
        }
        if (replacement->next == NULL)
        {
            parent->child->prev = replacement;
        }
    }

    item->next = NULL;
    item->prev = NULL;
    cJSON_Delete(item);

    return true;
}

CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
{
    if (which < 0)
    {
        return false;
    }

    return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
}

static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
{
    if ((replacement == NULL) || (string == NULL))
    {
        return false;
    }

    /* replace the name in the replacement */
    if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
    {
        cJSON_free(replacement->string);
    }
    replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
    replacement->type &= ~cJSON_StringIsConst;

    return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
}

CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
{
    return replace_item_in_object(object, string, newitem, false);
}

CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
{
    return replace_item_in_object(object, string, newitem, true);
}

/* Create basic types: */
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
{
    cJSON *item = cJSON_New_Item(&global_hooks);
    if(item)
    {
        item->type = cJSON_NULL;
    }

    return item;
}

/* 创建一个 cJSON True 类型的项 */
/* 此函数创建一个新的 cJSON 项并将其初始化为 True 布尔类型 */
/* 参数: 无 */
/* 返回值: 指向新创建的 cJSON True 项的指针，如果内存分配失败则返回 NULL */
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
{
    cJSON *item = cJSON_New_Item(&global_hooks);
    if(item)
    {
        item->type = cJSON_True;
    }

    return item;
}

/* 创建一个 cJSON False 类型的项 */
/* 此函数创建一个新的 cJSON 项并将其初始化为 False 布尔类型 */
/* 参数: 无 */
/* 返回值: 指向新创建的 cJSON False 项的指针，如果内存分配失败则返回 NULL */
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
{
    cJSON *item = cJSON_New_Item(&global_hooks);
    if(item)
    {
        item->type = cJSON_False;
    }

    return item;
}

/* 创建一个 cJSON 布尔类型的项 */
/* 此函数根据提供的布尔值创建一个新的 cJSON 项并将其初始化为相应的布尔类型 */
/* 参数: boolean - 要设置的布尔值，true 表示 cJSON_True，false 表示 cJSON_False */
/* 返回值: 指向新创建的 cJSON 布尔项的指针，如果内存分配失败则返回 NULL */
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
{
    cJSON *item = cJSON_New_Item(&global_hooks);
    if(item)
    {
        item->type = boolean ? cJSON_True : cJSON_False;
    }

    return item;
}

/* 创建一个 cJSON 数字类型的项 */
/* 此函数创建一个新的 cJSON 项并将其初始化为数字类型，同时设置其值 */
/* 参数: num - 要设置的数字值 */
/* 返回值: 指向新创建的 cJSON 数字项的指针，如果内存分配失败则返回 NULL */
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
{
    cJSON *item = cJSON_New_Item(&global_hooks);
    if(item)
    {
        item->type = cJSON_Number;
        item->valuedouble = num;

        /* use saturation in case of overflow */
        if (num >= INT_MAX)
        {
            item->valueint = INT_MAX;
        }
        else if (num <= (double)INT_MIN)
        {
            item->valueint = INT_MIN;
        }
        else
        {
            item->valueint = (int)num;
        }
    }

    return item;
}

/* 创建一个 cJSON 字符串类型的项 */
/* 此函数创建一个新的 cJSON 项并将其初始化为字符串类型，同时复制提供的字符串值 */
/* 参数: string - 用于初始化 cJSON 项的字符串值（将被复制） */
/* 返回值: 指向新创建的 cJSON 字符串项的指针，如果内存分配失败则返回 NULL */
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
{
    /* 使用全局钩子创建新的 cJSON 项 */
    cJSON *item = cJSON_New_Item(&global_hooks);
    /* 如果项创建成功，设置其类型和值 */
    if(item)
    {
        /* 将项类型设置为字符串 */
        item->type = cJSON_String;
        /* 复制输入字符串并分配给项的 valuestring */
        item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
        /* 如果字符串复制失败，清理并返回 NULL */
        if(!item->valuestring)
        {
            cJSON_Delete(item);
            return NULL;
        }
    }

    /* 返回创建的字符串项（如果创建失败则返回 NULL） */
    return item;
}

CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
{
    cJSON *item = cJSON_New_Item(&global_hooks);
    if (item != NULL)
    {
        item->type = cJSON_String | cJSON_IsReference;
        item->valuestring = (char*)cast_away_const(string);
    }

    return item;
}

CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
{
    cJSON *item = cJSON_New_Item(&global_hooks);
    if (item != NULL) {
        item->type = cJSON_Object | cJSON_IsReference;
        item->child = (cJSON*)cast_away_const(child);
    }

    return item;
}

CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
    cJSON *item = cJSON_New_Item(&global_hooks);
    if (item != NULL) {
        item->type = cJSON_Array | cJSON_IsReference;
        item->child = (cJSON*)cast_away_const(child);
    }

    return item;
}

CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
{
    cJSON *item = cJSON_New_Item(&global_hooks);
    if(item)
    {
        item->type = cJSON_Raw;
        item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
        if(!item->valuestring)
        {
            cJSON_Delete(item);
            return NULL;
        }
    }

    return item;
}

/* 创建一个 cJSON 数组类型的项 */
/* 此函数创建一个新的 cJSON 项并将其初始化为数组类型 */
/* 参数: 无 */
/* 返回值: 指向新创建的 cJSON 数组的指针，如果内存分配失败则返回 NULL */
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
{
    /* 使用全局钩子创建新的 cJSON 项 */
    cJSON *item = cJSON_New_Item(&global_hooks);
    /* 如果项创建成功，将其类型设置为数组 */
    if(item)
    {
        item->type=cJSON_Array;
    }

    /* 返回创建的数组（如果创建失败则返回 NULL） */
    return item;
}

/* 创建一个 cJSON 对象类型的项 */
/* 此函数创建一个新的 cJSON 项并将其初始化为对象类型 */
/* 参数: 无 */
/* 返回值: 指向新创建的 cJSON 对象的指针，如果内存分配失败则返回 NULL */
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
{
    /* 使用全局钩子创建新的 cJSON 项 */
    cJSON *item = cJSON_New_Item(&global_hooks);
    /* 如果项创建成功，将其类型设置为对象 */
    if (item)
    {
        item->type = cJSON_Object;
    }

    /* 返回创建的对象（如果创建失败则返回 NULL） */
    return item;
}

/* 创建一个包含整数数组的 cJSON 数组项 */
/* 此函数创建一个新的 cJSON 数组项，其中包含指定的整数值 */
/* 参数: numbers - 指向整数数组的指针 */
/*       count - 数组中元素的数量 */
/* 返回值: 指向新创建的 cJSON 数组的指针，如果创建失败则返回 NULL */
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
{
    size_t i = 0;
    cJSON *n = NULL;
    cJSON *p = NULL;
    cJSON *a = NULL;

    if ((count < 0) || (numbers == NULL))
    {
        return NULL;
    }

    a = cJSON_CreateArray();

    for(i = 0; a && (i < (size_t)count); i++)
    {
        n = cJSON_CreateNumber(numbers[i]);
        if (!n)
        {
            cJSON_Delete(a);
            return NULL;
        }
        if(!i)
        {
            a->child = n;
        }
        else
        {
            suffix_object(p, n);
        }
        p = n;
    }

    if (a && a->child) {
        a->child->prev = n;
    }

    return a;
}

/* 创建一个包含浮点数数组的 cJSON 数组项 */
/* 此函数创建一个新的 cJSON 数组项，其中包含指定的浮点数值 */
/* 参数: numbers - 指向浮点数数组的指针 */
/*       count - 数组中元素的数量 */
/* 返回值: 指向新创建的 cJSON 数组的指针，如果创建失败则返回 NULL */
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
{
    size_t i = 0;
    cJSON *n = NULL;
    cJSON *p = NULL;
    cJSON *a = NULL;

    if ((count < 0) || (numbers == NULL))
    {
        return NULL;
    }

    a = cJSON_CreateArray();

    for(i = 0; a && (i < (size_t)count); i++)
    {
        n = cJSON_CreateNumber((double)numbers[i]);
        if(!n)
        {
            cJSON_Delete(a);
            return NULL;
        }
        if(!i)
        {
            a->child = n;
        }
        else
        {
            suffix_object(p, n);
        }
        p = n;
    }

    if (a && a->child) {
        a->child->prev = n;
    }

    return a;
}

/* 创建一个包含双精度浮点数数组的 cJSON 数组项 */
/* 此函数创建一个新的 cJSON 数组项，其中包含指定的双精度浮点数值 */
/* 参数: numbers - 指向双精度浮点数数组的指针 */
/*       count - 数组中元素的数量 */
/* 返回值: 指向新创建的 cJSON 数组的指针，如果创建失败则返回 NULL */
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
{
    size_t i = 0;
    cJSON *n = NULL;
    cJSON *p = NULL;
    cJSON *a = NULL;

    if ((count < 0) || (numbers == NULL))
    {
        return NULL;
    }

    a = cJSON_CreateArray();

    for(i = 0; a && (i < (size_t)count); i++)
    {
        n = cJSON_CreateNumber(numbers[i]);
        if(!n)
        {
            cJSON_Delete(a);
            return NULL;
        }
        if(!i)
        {
            a->child = n;
        }
        else
        {
            suffix_object(p, n);
        }
        p = n;
    }

    if (a && a->child) {
        a->child->prev = n;
    }

    return a;
}

/* 创建一个包含字符串数组的 cJSON 数组项 */
/* 此函数创建一个新的 cJSON 数组项，其中包含指定的字符串值 */
/* 参数: strings - 指向字符串数组的指针 */
/*       count - 数组中元素的数量 */
/* 返回值: 指向新创建的 cJSON 数组的指针，如果创建失败则返回 NULL */
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count)
{
    size_t i = 0;
    cJSON *n = NULL;
    cJSON *p = NULL;
    cJSON *a = NULL;

    if ((count < 0) || (strings == NULL))
    {
        return NULL;
    }

    a = cJSON_CreateArray();

    for (i = 0; a && (i < (size_t)count); i++)
    {
        n = cJSON_CreateString(strings[i]);
        if(!n)
        {
            cJSON_Delete(a);
            return NULL;
        }
        if(!i)
        {
            a->child = n;
        }
        else
        {
            suffix_object(p,n);
        }
        p = n;
    }

    if (a && a->child) {
        a->child->prev = n;
    }
    
    return a;
}

/* 复制 cJSON 项 */
/* 此函数创建一个 cJSON 项及其所有子项的副本 */
/* 参数: item - 要复制的 cJSON 项 */
/*       recurse - 是否递归复制子项，true 表示递归复制，false 表示只复制当前项 */
/* 返回值: 指向新创建的 cJSON 项副本的指针，如果复制失败则返回 NULL */
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
{
    cJSON *newitem = NULL;
    cJSON *child = NULL;
    cJSON *next = NULL;
    cJSON *newchild = NULL;

    /* 检查空指针 */
    if (!item)
    {
        goto fail;
    }
    /* 创建新项 */
    newitem = cJSON_New_Item(&global_hooks);
    if (!newitem)
    {
        goto fail;
    }
    /* 复制所有变量 */
    newitem->type = item->type & (~cJSON_IsReference);
    newitem->valueint = item->valueint;
    newitem->valuedouble = item->valuedouble;
    if (item->valuestring)
    {
        newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
        if (!newitem->valuestring)
        {
            goto fail;
        }
    }
    if (item->string)
    {
        newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
        if (!newitem->string)
        {
            goto fail;
        }
    }
    /* 如果不递归，则完成！*/
    if (!recurse)
    {
        return newitem;
    }
    /* 遍历子项的 ->next 链 */
    child = item->child;
    while (child != NULL)
    {
        newchild = cJSON_Duplicate(child, true); /* 递归复制 ->next 链中的每一项 */
        if (!newchild)
        {
            goto fail;
        }
        if (next != NULL)
        {
            /* 如果 newitem->child 已设置，则连接 ->prev 和 ->next 并继续 */
            next->next = newchild;
            newchild->prev = next;
            next = newchild;
        }
        else
        {
            /* 设置 newitem->child 并移动到它 */
            newitem->child = newchild;
            next = newchild;
        }
        child = child->next;
    }
    if (newitem && newitem->child)
    {
        newitem->child->prev = newchild;
    }

    return newitem;

fail:
    if (newitem != NULL)
    {
        cJSON_Delete(newitem);
    }

    return NULL;
}

static void skip_oneline_comment(char **input)
{
    *input += static_strlen("//");

    for (; (*input)[0] != '\0'; ++(*input))
    {
        if ((*input)[0] == '\n') {
            *input += static_strlen("\n");
            return;
        }
    }
}

/**
 * @brief Skip and remove multiline comment blocks from JSON string during minification
 * This function advances the input pointer past C-style multiline comments (/* ... * /)
 * to eliminate comments from JSON while preserving the actual JSON content structure
 * @param input: Double pointer to current position in JSON string being processed
 *               The pointer is advanced to skip the entire multiline comment block
 */
static void skip_multiline_comment(char **input)
{
    /* Advance input pointer past the opening comment delimiter '/*' */
    *input += static_strlen("/*");

    /* Iterate through the input string until end of string is reached */
    for (; (*input)[0] != '\0'; ++(*input))
    {
        /* Check for the closing comment delimiter '* /' pattern */
        if (((*input)[0] == '*') && ((*input)[1] == '/'))
        {
            /* Advance pointer past the closing delimiter to continue processing */
            *input += static_strlen("*/");
            return;
        }
    }
}

/**
 * @brief Process and preserve string literals during JSON minification
 * This function carefully handles JSON string values during minification to ensure
 * that quoted strings remain intact while removing unnecessary whitespace outside strings
 * @param input: Double pointer to current position in source JSON string
 * @param output: Double pointer to current position in minified output buffer
 *                The output buffer receives the preserved string content
 */
static void minify_string(char **input, char **output) {
    /* Copy the opening quote character from input to output buffer */
    (*output)[0] = (*input)[0];
    /* Advance both input and output pointers past the opening quote */
    *input += static_strlen("\"");
    *output += static_strlen("\"");

    /* Process string content character by character until closing quote */
    for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
        /* Copy current character from input to output buffer */
        (*output)[0] = (*input)[0];

        /* Check for closing quote that terminates the string literal */
        if ((*input)[0] == '\"') {
            /* Ensure closing quote is properly placed in output */
            (*output)[0] = '\"';
            /* Advance pointers past the closing quote */
            *input += static_strlen("\"");
            *output += static_strlen("\"");
            return;
        } 
        /* Handle escaped quotes within string literals (\\") */
        else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
            /* Copy the escaped quote sequence to output */
            (*output)[1] = (*input)[1];
            /* Advance pointers past the escaped quote sequence */
            *input += static_strlen("\"");
            *output += static_strlen("\"");
        }
    }
}

/**
 * @brief Remove all unnecessary whitespace and comments from JSON string
 * This minification function optimizes JSON by eliminating whitespace, comments,
 * and other non-essential characters while preserving the structural integrity
 * @param json: Input JSON string that will be minified in-place
 *              The string is modified directly to reduce memory footprint
 */
CJSON_PUBLIC(void) cJSON_Minify(char *json)
{
    /* Pointer to track position in output (minified) buffer */
    char *into = json;

    /* Safety check: return immediately if input JSON is NULL */
    if (json == NULL)
    {
        return;
    }

    /* Process each character in the input JSON string sequentially */
    while (json[0] != '\0')
    {
        /* Switch based on current character type for appropriate processing */
        switch (json[0])
        {
            /* Whitespace characters that should be removed during minification */
            case ' ':
            case '\t':
            case '\r':
            case '\n':
                /* Simply skip whitespace by advancing input pointer */
                json++;
                break;

            /* Comment processing for both single-line and multi-line comments */
            case '/':
                /* Check for single-line comments starting with '//' */
                if (json[1] == '/')
                {
                    skip_oneline_comment(&json);
                }
                /* Check for multi-line comments starting with '/*' */
                else if (json[1] == '*')
                {
                    skip_multiline_comment(&json);
                } else {
                    /* Not a comment - treat as regular character */
                    json++;
                }
                break;

            /* String literal processing - preserve entire string content */
            case '\"':
                minify_string(&json, (char**)&into);
                break;

            /* Regular JSON characters that should be copied to output */
            default:
                into[0] = json[0];
                json++;
                into++;
        }
    }

    /* Null-terminate the minified JSON string to ensure proper string termination */
    *into = '\0';
}

/**
 * @brief Check if cJSON item represents an invalid or malformed JSON element
 * This validation function determines whether a cJSON object has been marked
 * as invalid due to parsing errors or structural issues in the JSON data
 * @param item: Pointer to cJSON structure to check for invalid status
 * @return cJSON_bool Returns true if item is invalid, false if valid or NULL
 */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
{
    /* Return false immediately if null pointer is provided */
    if (item == NULL)
    {
        return false;
    }

    /* Check if the item's type matches the cJSON_Invalid type flag */
    return (item->type & 0xFF) == cJSON_Invalid;
}

/**
 * @brief Determine if cJSON item represents a boolean false value
 * This function checks whether the provided cJSON object contains
 * a literal false value as defined in the JSON specification
 * @param item: Pointer to cJSON structure to check for false value
 * @return cJSON_bool Returns true if item is false, false otherwise or if NULL
 */
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
{
    /* Return false for null pointers to prevent segmentation faults */
    if (item == NULL)
    {
        return false;
    }

    /* Compare item type with cJSON_False constant using bitmask */
    return (item->type & 0xFF) == cJSON_False;
}

/**
 * @brief Determine if cJSON item represents a boolean true value
 * This function verifies whether the cJSON object contains a literal
 * true value according to JSON boolean representation standards
 * @param item: Pointer to cJSON structure to check for true value
 * @return cJSON_bool Returns true if item is true, false otherwise or if NULL
 */
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
{
    /* Handle null pointer case with safe return value */
    if (item == NULL)
    {
        return false;
    }

    /* Extract type bits and compare with cJSON_True constant */
    return (item->type & 0xff) == cJSON_True;
}

/**
 * @brief Check if cJSON item represents any boolean value (true or false)
 * This function provides a generalized boolean check that returns true
 * for both cJSON_True and cJSON_False type items in the JSON structure
 * @param item: Pointer to cJSON structure to check for boolean type
 * @return cJSON_bool Returns true if item is boolean, false otherwise or if NULL
 */
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
{
    /* Return false for null pointers to ensure safe operation */
    if (item == NULL)
    {
        return false;
    }

    /* Bitwise OR check for either true or false type flags */
    return (item->type & (cJSON_True | cJSON_False)) != 0;
}

/**
 * @brief Determine if cJSON item represents a JSON null value
 * This function checks whether the provided cJSON object contains
 * a null value as specified in the JSON data interchange format
 * @param item: Pointer to cJSON structure to check for null value
 * @return cJSON_bool Returns true if item is null, false otherwise or if NULL
 */
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
{
    /* Safety check for null input pointer */
    if (item == NULL)
    {
        return false;
    }

    /* Compare extracted type bits with cJSON_NULL constant */
    return (item->type & 0xFF) == cJSON_NULL;
}

/**
 * @brief Check if cJSON item represents a numeric JSON value
 * This function identifies whether the cJSON object contains a number
 * which can be either integer or floating-point in JSON representation
 * @param item: Pointer to cJSON structure to check for number type
 * @return cJSON_bool Returns true if item is number, false otherwise or if NULL
 */
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
{
    /* Handle null pointer case gracefully */
    if (item == NULL)
    {
        return false;
    }

    /* Verify that item type matches cJSON_Number type constant */
    return (item->type & 0xFF) == cJSON_Number;
}

/**
 * @brief Determine if cJSON item represents a string JSON value
 * This function checks whether the provided cJSON object contains
 * a string value with proper quotation and character encoding
 * @param item: Pointer to cJSON structure to check for string type
 * @return cJSON_bool Returns true if item is string, false otherwise or if NULL
 */
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
{
    /* Return false for null input pointers */
    if (item == NULL)
    {
        return false;
    }

    /* Compare type bits with cJSON_String type identifier */
    return (item->type & 0xFF) == cJSON_String;
}

/**
 * @brief Check if cJSON item represents a JSON array structure
 * This function identifies array objects in the JSON hierarchy
 * which contain ordered collections of other JSON values
 * @param item: Pointer to cJSON structure to check for array type
 * @return cJSON_bool Returns true if item is array, false otherwise or if NULL
 */
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
{
    /* Null pointer safety check */
    if (item == NULL)
    {
        return false;
    }

    /* Verify item type matches cJSON_Array constant */
    return (item->type & 0xFF) == cJSON_Array;
}

/**
 * @brief Determine if cJSON item represents a JSON object structure
 * This function checks for JSON objects which are unordered collections
 * of key-value pairs with string keys and JSON values
 * @param item: Pointer to cJSON structure to check for object type
 * @return cJSON_bool Returns true if item is object, false otherwise or if NULL
 */
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
{
    /* Handle null pointer case to prevent crashes */
    if (item == NULL)
    {
        return false;
    }

    /* Compare type with cJSON_Object type identifier */
    return (item->type & 0xFF) == cJSON_Object;
}

/**
 * @brief Check if cJSON item represents a raw JSON value
 * This function identifies raw JSON items that contain unparsed
 * JSON text which should be inserted directly during serialization
 * @param item: Pointer to cJSON structure to check for raw type
 * @return cJSON_bool Returns true if item is raw, false otherwise or if NULL
 */
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
{
    /* Safety check for null input parameter */
    if (item == NULL)
    {
        return false;
    }

    /* Verify item type matches cJSON_Raw type constant */
    return (item->type & 0xFF) == cJSON_Raw;
}

/**
 * @brief Compare two cJSON structures for deep equality
 * This comprehensive comparison function performs deep structural
 * comparison of two cJSON objects including all nested elements
 * @param a: First cJSON object to compare in the equality check
 * @param b: Second cJSON object to compare against the first
 * @param case_sensitive: Flag indicating whether string comparisons
 *                       should respect character case differences
 * @return cJSON_bool Returns true if objects are deeply equal,
 *                   false if different or either parameter is NULL
 */
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
{
    /* Preliminary validation: check for null pointers and type mismatch */
    if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)))
    {
        return false;
    }

    /* Comprehensive type validation switch for supported JSON types */
    /* check if type is valid */
    switch (a->type & 0xFF)
    {
        /* All valid JSON types that support comparison operations */
        case cJSON_False:
        case cJSON_True:
        case cJSON_NULL:
        case cJSON_Number:
        case cJSON_String:
        case cJSON_Raw:
        case cJSON_Array:
        case cJSON_Object:
            break;

        /* Invalid or unsupported types result in comparison failure */
        default:
            return false;
    }

    /* Identity check: if both pointers reference the same object, they are equal */
    /* identical objects are equal */
    if (a == b)
    {
        return true;
    }

    /* Type-specific comparison logic for different JSON value types */
    switch (a->type & 0xFF)
    {
        /* Simple types where identical type implies identical value */
        case cJSON_False:
        case cJSON_True:
        case cJSON_NULL:
            return true;

        /* Numeric comparison with floating-point precision handling */
        case cJSON_Number:
            if (compare_double(a->valuedouble, b->valuedouble))
            {
                return true;
            }
            return false;

        /* String and raw JSON comparison with optional case sensitivity */
        case cJSON_String:
        case cJSON_Raw:
            if ((a->valuestring == NULL) || (b->valuestring == NULL))
            {
                return false;
            }
            if (strcmp(a->valuestring, b->valuestring) == 0)
            {
                return true;
            }

            return false;

        /* Array comparison requiring identical element count and order */
        case cJSON_Array:
        {
            cJSON *a_element = a->child;
            cJSON *b_element = b->child;

            /* Iterate through both arrays simultaneously */
            for (; (a_element != NULL) && (b_element != NULL);)
            {
                /* Recursive comparison of array elements */
                if (!cJSON_Compare(a_element, b_element, case_sensitive))
                {
                    return false;
                }

                /* Advance to next elements in both arrays */
                a_element = a_element->next;
                b_element = b_element->next;
            }

            /* Check if both arrays have the same number of elements */
            /* one of the arrays is longer than the other */
            if (a_element != b_element) {
                return false;
            }

            return true;
        }

        /* Object comparison requiring identical keys and values */
        case cJSON_Object:
        {
            cJSON *a_element = NULL;
            cJSON *b_element = NULL;
            
            /* First pass: check all keys in object A exist in object B */
            cJSON_ArrayForEach(a_element, a)
            {
                /* TODO This has O(n^2) runtime, which is horrible! */
                b_element = get_object_item(b, a_element->string, case_sensitive);
                if (b_element == NULL)
                {
                    return false;
                }

                /* Compare values for matching keys */
                if (!cJSON_Compare(a_element, b_element, case_sensitive))
                {
                    return false;
                }
            }

            /* Second pass: check all keys in object B exist in object A */
            /* doing this twice, once on a and b to prevent true comparison if a subset of b
             * TODO: Do this the proper way, this is just a fix for now */
            cJSON_ArrayForEach(b_element, b)
            {
                a_element = get_object_item(a, b_element->string, case_sensitive);
                if (a_element == NULL)
                {
                    return false;
                }

                /* Compare values for matching keys in reverse direction */
                if (!cJSON_Compare(b_element, a_element, case_sensitive))
                {
                    return false;
                }
            }

            return true;
        }

        /* Fallback for unexpected types */
        default:
            return false;
    }
}

/**
 * @brief Allocate memory using the configured global memory hooks
 * This function provides abstracted memory allocation that uses the
 * currently configured allocation function from the global hooks
 * @param size: Number of bytes to allocate for cJSON operations
 * @return void* Returns pointer to allocated memory or NULL if allocation fails
 */
CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
{
    return global_hooks.allocate(size);
}

/**
 * @brief Deallocate memory using the configured global memory hooks
 * This function provides abstracted memory deallocation that uses the
 * currently configured deallocation function from the global hooks
 * @param object: Pointer to memory block previously allocated by cJSON_malloc
 */
CJSON_PUBLIC(void) cJSON_free(void *object)
{
    global_hooks.deallocate(object);
}